<template>
    <div class="flex flex-col w-full h-full">
      <n-space justify="end">
        <n-statistic  :value="currentSelectNum + 1 ">
          <template #prefix>
            <n-icon @click="preBoard ">
              <n-el style="color: var(--primary-color)">
               <ChevronBackCircleSharp />
              </n-el>
            </n-icon>
          </template>
          <template #suffix>
            / {{storyBoardList.length}}
            <n-icon  @click="nextBoard">
              <n-el style="color: var(--primary-color)">
                  <ChevronForwardCircleSharp  />
              </n-el>
            </n-icon>
          </template>
        </n-statistic>
      </n-space>
        <n-grid :x-gap="24">
            <n-grid-item span="6">
                <n-form  :model="storyPaintConfig" :rules="rules" ref="formRef">
                  <n-form-item label="资源选择" path="resourceId">
                    <n-select v-model:value="storyPaintConfig.resourceId" :options="resourceOption"  @update:value="resourceSelect">
                    </n-select>
                  </n-form-item>
                  <n-form-item label="风格预设" path="defaultStyleId">
                    <n-select v-model:value="storyPaintConfig.defaultStyleId" :default-value="1">
                    </n-select>
                  </n-form-item>
                  <n-form-item label="尺寸设置" path="sizeOption">
                    <n-select
                        :options="sizeOption"
                        v-model:value="storyPaintConfig.sizeOption"
                    />
                  </n-form-item>
                  <n-form-item label="测试提示词" path="prompt">
                    <n-input v-model:value="demoPrompt"  type="textarea" placeholder="请输入测试提示词" />
                  </n-form-item>
                  <n-form-item label="预设正向提示词" path="defaultPrompt">
                    <n-input v-model:value="storyPaintConfig.defaultPrompt"  type="textarea" placeholder="请输入预设正向提示词" />
                  </n-form-item>
                  <n-form-item label="预设反向提示词" path="defaultNegativePrompt">
                    <n-input placeholder="请输入反向提示词"  type="textarea" v-model:value="storyPaintConfig.defaultNegativePrompt" />
                  </n-form-item>
                </n-form>
            </n-grid-item>
            <n-grid-item span="10">
                <n-el style="background: var(--hover-color);margin-top:10px">
                    <n-space justify="center"  style="padding: 10px;height: 300px">
                        <n-image
                            height="300"
                            :src=fileFunction.getViewFilePathByUserFileId(selectBoard.imgFileId)
                        />
                    </n-space>
                </n-el>
              <n-space   style="margin-top:20px" >
                <n-scrollbar  x-scrollable style="max-height: 80px">
                  <div style="white-space: nowrap;" >
                    <n-image v-for="storyPaintLog in selectBoard.storyPaintLogs"
                             preview-disabled
                             :lazy="true"
                             :width="70"
                             size="small"
                             @click="clickImg(storyPaintLog)"
                             :class="{ 'selected': selectBoard.imgFileId=== storyPaintLog.fileId }"
                             style="margin-left: 10px;"
                             :src=fileFunction.getViewFilePathByUserFileId(storyPaintLog.fileId)
                    />
                  </div>
                </n-scrollbar>
              </n-space>
                <n-button block type="primary" size="large"
                          :loading="buttonLoading" style="margin-top: 20px" @click="paintTest">抽卡</n-button>
              <n-button block type="primary" size="large"
                        :loading="buttonLoading" style="margin-top: 20px" @click="rechosePic">设为本镜图片</n-button>
            </n-grid-item>
          <n-grid-item span="8">
              <n-scrollbar style="max-height: 600px">
                <n-spin :show="resourceLoading">
                  <n-tabs type="line" animated>
                    <n-tab-pane name="模型设置" tab="模型设置">
                      <n-form :model="storyPaintConfig" :rules="rules" ref="formRef">
                        <n-form-item label="StableDiffusion模型" path="defaultModel">
                          <n-select v-model:value="storyPaintConfig.defaultModel" :options="modelOption" @update:value="changeModel"/>
                        </n-form-item>
                        <n-form-item label="外观VAE模型" path="defaultVae">
                          <n-select
                              :options="vaeOption" v-model:value="storyPaintConfig.defaultVae" @update:value="changeVae"
                          />
                        </n-form-item>
                      </n-form>
                      <n-tabs type="segment">
                        <n-tab-pane name="chap1" tab="Lora">
                          <n-grid x-gap="12" :cols="3">
                            <n-gi v-for="lora in loraList">
                              <n-card v-if="lora.name.length > 0">
                                <n-space> {{lora.name}}</n-space>
                              </n-card>
                            </n-gi>
                          </n-grid>
                        </n-tab-pane>
                      </n-tabs>
                    </n-tab-pane>
                    <n-tab-pane name="参数设置" tab="参数设置">
                      <n-form :model="storyPaintConfig" :rules="rules" ref="formRef">
                        <n-form-item label="随机种子" path="defaultSeed">
                          <n-input-number v-model:value="storyPaintConfig.defaultSeed" />
                        </n-form-item>
                        <n-form-item label="ADetailer脸部修复" path="defaultRestoreFaces">
                          <n-checkbox v-model:checked="storyPaintConfig.defaultRestoreFaces" >
                            ADetailer脸部修复
                          </n-checkbox>
                        </n-form-item>
                        <n-form-item label="高清修复" path="defaultEnableHr">
                          <n-checkbox v-model:checked="storyPaintConfig.defaultEnableHr">
                            高清修复
                          </n-checkbox>
                        </n-form-item>
                        <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="方法算法" path="defaultHrUpscaler">
                          <n-select v-model:value="storyPaintConfig.defaultHrUpscaler" :options="hrUpscalerOptions">
                          </n-select>
                        </n-form-item>

                        <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="采样步数" path="defaultHrSecondPassSteps">
                          <n-input-number v-model:value="storyPaintConfig.defaultHrSecondPassSteps" :min="1" :max="150" :step="1"/>
                        </n-form-item>

                        <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="重绘幅度" path="defaultDenoisingStrength">
                          <n-input-number v-model:value="storyPaintConfig.defaultDenoisingStrength" :min="0" :max="1.0" :step="0.01"/>
                        </n-form-item>

                        <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="放大倍率" path="defaultHrScale">
                          <n-input-number v-model:value="storyPaintConfig.defaultHrScale" :min="1" :max="4" :step="0.05"/>
                        </n-form-item>

                        <n-form-item label="随机种子" path="defaultSeed">
                          <n-input-number v-model:value="storyPaintConfig.defaultSeed" />
                        </n-form-item>

                        <n-form-item label="采样器" path="defaultSamplerName">
                          <n-select
                              :options="samplerOptions" v-model:value="storyPaintConfig.defaultSamplerName" placeholder="请选择"
                          />
                        </n-form-item>
                        <n-form-item label="提示词相关度" path="defaultCfgScale">
                          <n-input-number v-model:value="storyPaintConfig.defaultCfgScale" />
                        </n-form-item>
                        <n-form-item label="批次数量" path="defaultBatchSize">
                          <n-input-number v-model:value="storyPaintConfig.defaultBatchSize" />
                        </n-form-item>
                        <n-form-item label="采样迭代步数" path="defaultSteps">
                          <n-input-number v-model:value="storyPaintConfig.defaultSteps"/>
                        </n-form-item>
                      </n-form>
                    </n-tab-pane>
                  </n-tabs>
                </n-spin>
              </n-scrollbar>
          </n-grid-item>
      </n-grid>
    </div>
</template>

<script setup lang="ts">
  import {computed, onMounted, reactive, ref} from 'vue';
  import {useMessage } from 'naive-ui';
  import {resourceController} from '@/api/resource/resourceController.api'
  import {storyController} from '@/api/story/story.api'
  import {sdControllerApi} from "@/api/sd/sdController.api";
  // @ts-ignore
  import fileFunction from "@/libs/globalFunction/file";
  import {ChevronBackCircleSharp,ChevronForwardCircleSharp}  from '@vicons/ionicons5'

  // 加载资源配置Loading
  const resourceLoading = ref(false)
  const resourceConfig = ref(null)
  const resourceOption = ref([])
  const selectedResource = ref("")
  const modelOption = ref([])
  const vaeOption = ref([])
  const loraList = ref([])
  const formRef: any = ref(null);
  const message = useMessage();
  const taskStatus = ref("waiting");
  const buttonLoading = ref(false)

  const props = defineProps({
    storyBoardList:{
      type: Array,
      default: () => {
        return []
      }
    },
    selectNum:{
      type: Number,
      default: () => {
        return {}
      }
    },
    reloadStoryBoards:{
      type: Function,
      default: () => {
        return {}
      }
    }
  })

  const currentSelectNum  = ref(props.selectNum)
  // 上一镜
  const preBoard = () => {
    if(currentSelectNum.value > 0){
      currentSelectNum.value = currentSelectNum.value - 1
    }
  }
  // 下一镜
  const nextBoard = () =>{
      console.log(currentSelectNum.value)
    if(currentSelectNum.value < props.storyBoardList.length - 1){
      currentSelectNum.value = currentSelectNum.value + 1
        console.log(currentSelectNum.value)
    }
  }

  // 当前的prompt
  const demoPrompt = ref("")


  // 当前选中的镜
  const selectBoard = computed(() => {
    demoPrompt.value = props.storyBoardList[currentSelectNum.value].prompt
    return props.storyBoardList[currentSelectNum.value]
  })



  const sizeOption =  [
    {
      label: '1:1 (640 * 640)',
      value: '1'
    },
    {
      label: '3:2 (768 * 512)',
      value: '2'
    },
    {
      label: '2:3 (512 * 768)',
      value: '3'
    }
  ]


  const rules = {
    resourceId: {
      required: true,
      message: '请选择资源',
      trigger: 'blur'
    },
    sizeOption: {
      required: true,
      message: '请选择尺寸信息',
      trigger: 'blur'
    },
    defaultModel: {
      required: true,
      message: '请选择模型',
      trigger: 'blur'
    },
    defaultVae:{
      required: true,
      message: '请选择模型',
      trigger: 'blur'
    }
  };

  // 绘画配置
  const storyPaintConfig  =  ref(reactive({
      paintType: 'SD',
      resourceId: '',
      defaultStyleId: '',
      defaultPrompt: '',
      defaultNegativePrompt: '',
      defaultSeed: -1,
      defaultSamplerName: 'DPM++ 2M',
      defaultBatchSize: 1,
      defaultSteps: 20,
      defaultWidth: 512,
      defaultHeight: 512,
      defaultCfgScale: 7,
      defaultModel: '',
      defaultVae: '',
      sizeOption:'',
      chapterId: selectBoard.value.chapterId,
      defaultVoiceName:'',
      defaultVolume:1.0,
      defaultRate:1.0,
      defaultPitch:1.0,
      voiceType:'free',
      defaultRestoreFaces : false,
      defaultEnableHr : false,
      defaultHrUpscaler : 'R-ESRGAN 4x+',
      defaultHrScale : 2 ,
      defaultDenoisingStrength : 0.50,
      defaultHrSecondPassSteps : 8
  }))


  const hrUpscalerOptions = [
    {
      label:"Latent",
      value:"Latent"
    },
    {
      label:"Latent (antialiased)",
      value:"Latent (antialiased)"
    },
    {
      label:"潜变量(bicubic)",
      value:"Latent (bicubic)"
    },
    {
      label:"Latent (bicubic antialiased)",
      value:"Latent (bicubic antialiased)"
    },
    {
      label:"Latent (nearest)",
      value:"Latent (nearest)"
    },
    {
      label:"Latent (nearest-exact)",
      value:"Latent (nearest-exact)"
    },
    {
      label:"None",
      value:"None"
    },
    {
      label:"Lanczos",
      value:"Lanczos"
    },
    {
      label:"Nearest",
      value:"Nearest"
    },
    {
      label:"BSRGAN",
      value:"BSRGAN"
    },
    {
      label:"ESRGAN_4x",
      value:"ESRGAN_4x"
    },
    {
      label:"LDSR",
      value:"LDSR"
    },
    {
      label:"R-ESRGAN 4x+",
      value:"R-ESRGAN 4x+"
    },
    {
      label:"R-ESRGAN 4x+ Anime6B",
      value:"R-ESRGAN 4x+ Anime6B"
    },
    {
      label:"ScuNET",
      value:"ScuNET"
    },
    {
      label:"ScuNET PSNR",
      value:"ScuNET PSNR"
    },
    {
      label:"SwinIR_4x",
      value:"SwinIR_4x"
    }
  ]

  const samplerOptions =[
    {
        label: 'DPM++ 2M Karras',
        value: 'DPM++ 2M Karras'
    },
    {
        label: 'k_heun',
        value: 'k_heun'
    },
    {
        label: "k_euler",
        value: 'k_euler'
    },
    {
        label: "k_euler_a",
        value: 'k_euler_a'
    },
    {
        label: "k_dpm_2",
        value: 'k_dpm_2'
    },
    {
        label: "k_dpm_2_a",
        value: 'k_dpm_2_a'
    },
    {
        label: "k_dpm_fast",
        value: 'k_dpm_fast'
    },
    {
        label: "k_dpm_adaptive",
        value: 'k_dpm_adaptive'
    },
    {
        label: "k_dpmpp_2s_a",
        value: 'k_dpmpp_2s_a'
    },
    {
        label: "k_dpmpp_2m",
        value: 'k_dpmpp_2m'
    },
    {
        label: "dpmsolver",
        value: 'dpmsolver'
    },
    {
        label: "k_dpmpp_sde",
        value: 'k_dpmpp_sde'
    },
    {
        label: "DDIM",
        value: 'DDIM'
    }
  ]

  /***
   * 获取绘画资源
   */
  const getResourceInfo = () =>{
    resourceController.getSDResource('SD').then(res=>{
      if(res.code === 200){
        res.data.forEach((item:any)=>{
          // @ts-ignore
          resourceOption.value.push({
              label: item.resourceName,
              value: item.id
            })
        })
        console.log(resourceOption.value)
      } else {
        message.error(res.msg);
      }
    })
  }

  // 获取SD资源详情
  const getResourceConfig = (resouceId:string) =>{
    resourceLoading.value = true
    resourceController.getReousceConfig(resouceId).then(res=>{
      resourceLoading.value = false
      if(res.code === 200){
        resourceConfig.value = res.data
        modelOption.value = []
        vaeOption.value = []
        loraList.value = []
        storyPaintConfig.value.defaultModel = res.data.selectModel
        storyPaintConfig.value.defaultVae = res.data.selectVae
        res.data.modelList.forEach((item:any)=>{
          console.log(item)
          // @ts-ignore
          modelOption.value.push({
            label: item,
            value: item
          })
        })
        res.data.vaeList.forEach((item:any)=>{
          // @ts-ignore
          vaeOption.value.push({
            label: item,
            value: item
          })
        })
        res.data.loraList.forEach((item:any)=>{
          if(item.length > 0 ) {
            // @ts-ignore
            loraList.value.push({
              name: item
            })
          }
        })
      } else {
        message.error(res.msg);
      }
    })
  }

  // 选中资源后
  const resourceSelect = (value:string) =>{
    selectedResource.value = value
    getResourceConfig(value)
  }



  const changeModel = (value:string) =>{
    // resourceController.cha
    const data = {
      resourceId: selectedResource.value,
      key : 'sd_model_checkpoint',
      value : value
    }
    changeOption(data)
  }

  const changeVae = (value:string) =>{
    const data = {
      resourceId: selectedResource.value,
      key : 'sd_vae',
      value : value
    }
    changeOption(data)
  }

  const changeOption = (data:any) =>{
    resourceLoading.value = true
    resourceController.changeOption(data).then(res=>{
      if(res.code === 200){
        getOption()
      } else {
        message.error(res.msg);
      }
    })
  }

  const getOption = () => {
    resourceController.getOptions(selectedResource.value).then(res=>{
      resourceLoading.value = false
      if(res.code === 200){
        message.success("修改成功")
      } else {
        message.error(res.msg);
      }
    })
  }

  const getStoryPaintConfig = (chapterId:string) =>{
    storyController.getStoryPaintConfig(chapterId).then(res=>{
      if(res.code === 200){
        if(res.data != null) {
          storyPaintConfig.value = res.data
          selectedResource.value = res.data.resourceId
          getResourceConfig(res.data.resourceId)
        }
      } else {
        message.error(res.msg);
      }
    })
  }

  const selectStoryPaintLog = ref(null)
  const clickImg = (storyPaintLog) => {
    selectStoryPaintLog.value = storyPaintLog
    selectBoard.value.imgFileId = storyPaintLog.fileId
  }

  onMounted(() => {
    getResourceInfo()
    getStoryPaintConfig(selectBoard.value.chapterId)
  });


  const paintTest =  async () => {
      // 更新prompt

      const data = {
        id : selectBoard.value.id,
        prompt: demoPrompt.value
      }
      const res = await storyController.updatePrompt(data)
      if(res.code != 200) {
        message.error(res.msg)
      }
      if(storyPaintConfig.value.paintType === 'SD'){
          const sdTxt2ImgPrompt : SD.Txt2ImgInput =  reactive({
              prompt: '',
              negativePrompt: '',
              seed: -1,
              samplerName: 'DPM++ 2M',
              batchSize: 1,
              steps: 20,
              width: 512,
              height: 512,
              promptEn: '',
              cfgScale: 7,
              savePath: '',
              restoreFaces : false,
              enableHr: false,
              hrUpscaler: 'R-ESRGAN 4x+',
              hrScale: 2.0,
              denoisingStrength: 0.5,
              hrSecondPassSteps: 8
          });
          sdTxt2ImgPrompt.prompt = demoPrompt.value + "," + storyPaintConfig.value.defaultPrompt;
          sdTxt2ImgPrompt.negativePrompt = storyPaintConfig.value.defaultNegativePrompt;
          sdTxt2ImgPrompt.seed = storyPaintConfig.value.defaultSeed;
          sdTxt2ImgPrompt.samplerName = storyPaintConfig.value.defaultSamplerName;
          sdTxt2ImgPrompt.batchSize = storyPaintConfig.value.defaultBatchSize;
          sdTxt2ImgPrompt.steps = storyPaintConfig.value.defaultSteps;
          sdTxt2ImgPrompt.cfgScale = storyPaintConfig.value.defaultCfgScale;
          sdTxt2ImgPrompt.sdResourceId  = storyPaintConfig.value.resourceId
          sdTxt2ImgPrompt.storyBoardId = selectBoard.value.id
          // 脸部修复
          if(storyPaintConfig.value.defaultRestoreFaces){
            sdTxt2ImgPrompt.restoreFaces = storyPaintConfig.value.defaultRestoreFaces
          }
          // 高清修复
          if(storyPaintConfig.value.defaultEnableHr){
            sdTxt2ImgPrompt.enableHr = storyPaintConfig.value.defaultEnableHr
            sdTxt2ImgPrompt.hrUpscaler = storyPaintConfig.value.defaultHrUpscaler
            sdTxt2ImgPrompt.hrScale = storyPaintConfig.value.defaultHrScale
            sdTxt2ImgPrompt.hrSecondPassSteps = storyPaintConfig.value.defaultHrSecondPassSteps
            sdTxt2ImgPrompt.denoisingStrength = storyPaintConfig.value.defaultDenoisingStrength
          }
          if(storyPaintConfig.value.sizeOption === "1"){
              sdTxt2ImgPrompt.width = 640
              sdTxt2ImgPrompt.height = 640
          }else if(storyPaintConfig.value.sizeOption ==="2"){
              sdTxt2ImgPrompt.width = 768
              sdTxt2ImgPrompt.height = 512
          }else {
              sdTxt2ImgPrompt.width=512
              sdTxt2ImgPrompt.height=768
          }
          buttonLoading.value = true;
          const res = await storyController.text2Img(sdTxt2ImgPrompt)
          if(res.code === 200){
              const data = res.data;
              if(data.code === 1){
                  checkTask(data.result);
              }
          }else {
              message.error(res.message);
          }
      }else {
          // sd
      }
  }

  let timeoutId = ref();// 保存当前的 setTimeout 的 id
  const checkTask = async (taskId:string) => {
      const response = await sdControllerApi.checkTask(taskId);
      if(response.code === 200){
          const data = response.data;
          taskStatus.value = data.status;
          if(data.taskStatus === "SUCCESS"){
              buttonLoading.value = false;
              clearTimeout(timeoutId.value);
              props.reloadStoryBoards()
          }else if(data.taskStatus === "FAILURE"){
              buttonLoading.value = false;
              clearTimeout(timeoutId.value);
              message.error(data.message);
          }else {
              timeoutId.value = setTimeout(() => {
                checkTask(taskId);
              }, 2000); //
          }
      }else {
          buttonLoading.value = false;
          clearTimeout(timeoutId.value); // 当任务完成时停止调用 checkTask
          message.error(response.msg);
      }
  }

  const rechosePic = () => {
    if(selectStoryPaintLog.value !== null){
      buttonLoading.value = true
      const data = {
        id : selectBoard.value.id,
        paintTaskId: selectStoryPaintLog.value.paintTaskId
      }
      storyController.updatePic(data).then(res=> {
        buttonLoading.value = false
        if (res.code === 200 ) {
          message.success('设置成功')
        } else {
          message.error(res.message)
        }
      })
    }

  }
</script>
